package com.lucenex.util;




import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
import org.apache.lucene.document.BinaryPoint;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FloatPoint;
import org.apache.lucene.document.IntPoint;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.NumericDocValuesField;
import org.apache.lucene.document.SortedDocValuesField;
import org.apache.lucene.document.SortedNumericDocValuesField;
import org.apache.lucene.document.SortedSetDocValuesField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.InvalidTokenOffsetsException;
import org.apache.lucene.util.BytesRef;
import org.nlpcn.commons.lang.pinyin.Pinyin;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ld.ThreadPool.LoggerFactory;
import com.lucenex.core.field.FieldKey;

/**
 * 对象转换类
 * @author zxw
 *
 */

public class ObjectKit{

	private static Logger logger = LoggerFactory.getLogger(ObjectKit.class);


	/**
	 * objects 转 documents
	 * @param objects
	 * @return
	 */
	public static List<Document> objToDocs(List<?> objects){
		if(objects == null || objects.isEmpty()) {
			return null;
		}
		List<Document> documents = new ArrayList<>();
		int size = objects.size();
		for (int i = 0; i < size; i++) {
			Object object = objects.get(i);
			System.out.println(i+"--->"+object);
			if(object != null) {
				documents.add(objToDoc(object));
			}
		}
		objects.clear();//清理元数据
		return documents;
	}

	/**
	 * maps 转 documents
	 * @param objects
	 * @return
	 */
	public static List<Document> mapToDocs(List<?> maps,Class<?> type){
		if(maps == null || maps.isEmpty()) {
			return null;
		}
		List<Document> documents = new ArrayList<>();
		int size = maps.size();
		for (int i = 0; i < size; i++) {
			Object object = JSONObject.parseObject(JSON.toJSONString(maps.get(i)), type);
			documents.add(objToDoc(object));
		}
		maps.clear();//清理元数据
		type = null;
		return documents;
	}

	/**
	 * object 转 document
	 * @param object
	 * @return
	 */
	public static Document objToDoc(Object object) {
		java.lang.reflect.Field[] declaredFields = object.getClass().getDeclaredFields();
		int j =declaredFields.length;
		java.lang.reflect.Field field;
		Document document = null;
		if(j > 0) {
			document = new Document();
			for(int i=0;i<j;i++) {
				field = declaredFields[i];
				field.setAccessible(true);
				//值为空 或 没有 指定注解
				if(field.isAnnotationPresent(FieldKey.class)) {
					try {
						add(document,field,object);
					} catch (IllegalAccessException e) {
						logger.log(Level.SEVERE, "objectKit objToDoc toField error", e);
					}
				}
			}
		}
		return document;
	}

	/**
	 * map 转 document
	 * @param object
	 * @param type
	 * @return
	 */
	public static Document mapToDoc(Object object,Class<?> type) {
		Object obj = JSONObject.parseObject(JSON.toJSONString(object), type);
		java.lang.reflect.Field[] declaredFields = obj.getClass().getDeclaredFields();
		int j =declaredFields.length;
		java.lang.reflect.Field field;
		Document document = null;
		if(j > 0) {
			document = new Document();
			for(int i=0;i<j;i++) {
				field = declaredFields[i];
				field.setAccessible(true);
				//值为空 或 没有 指定注解
				if(field.isAnnotationPresent(FieldKey.class)) {
					try {
						add(document,field,obj);
					} catch (IllegalAccessException e) {
						logger.log(Level.SEVERE, "objectKit objToDoc toField error", e);
					}
				}
			}
		}
		return document;
	}

	/**
	 * Document 转 Object
	 * @param doc
	 * @param clas
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 */
	public static <T> T object(Document doc,Class<T> clas){
		Iterator<IndexableField> iterator = doc.iterator();
		JSONObject o = new JSONObject();
		do {
			IndexableField next = iterator.next();
			o.put(next.name(), next.stringValue());
		} while (iterator.hasNext());
		return JSON.toJavaObject(o, clas);
	}


	/**
	 * Document 转 Object 高亮模式
	 * @param doc
	 * @param clas
	 * @param highlighter
	 * @param analyzer
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws NoSuchFieldException
	 * @throws SecurityException
	 * @throws IOException
	 * @throws InvalidTokenOffsetsException
	 */
	public static <T> T object(Document doc,Class<T> clas,Highlighter highlighter,PerFieldAnalyzerWrapper analyzer) throws InstantiationException, IllegalAccessException, NoSuchFieldException, IOException, InvalidTokenOffsetsException {
		Iterator<IndexableField> iterator = doc.iterator();
		JSONObject o = new JSONObject();
		do {
			IndexableField next = iterator.next();
			o.put(next.name(), next.stringValue());
		} while (iterator.hasNext());

		//设置高亮
		java.lang.reflect.Field[] fields = clas.getDeclaredFields();
		for (java.lang.reflect.Field field : fields) {
			if(!field.getAnnotation(FieldKey.class).highlight()) {
				continue;
			}
			String name = field.getName();
			String value = o.getString(name);
			if(value == null) {
				continue;
			}
			String token = highlighter.getBestFragment(analyzer.tokenStream(name, new StringReader(value)), value);
			o.put(name, token == null ? value : token);
		}
		return JSON.toJavaObject(o, clas);
	}

	/**
	 * 字段解析
	 * @param doc
	 * @param field
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 */
	private static void add(Document doc,java.lang.reflect.Field field,Object obj) throws IllegalAccessException {
		String value;
		Object object = field.get(obj);
		if(object != null) {
			value = object.toString();
		}else {
			return;
		}
		FieldKey fieldKey = field.getAnnotation(FieldKey.class);
		String name = field.getName();


		//字段存储
		switch (fieldKey.type()) {
		case IntPoint:
			int parseInt = Integer.parseInt(value);
			doc.add(new IntPoint(name,parseInt));
			doc.add(new StoredField(name,parseInt));
			break;
		case LongPoint:
			Long valueOf = Long.valueOf(value);
			doc.add(new LongPoint(name, valueOf));
			doc.add(new StoredField(name, valueOf));
			break;
		case DateField:
			long date = ((Date) field.get(obj)).getTime();
			doc.add(new LongPoint(name, date));
			doc.add(new StoredField(name, date));
			break;
		case FloatPoint:
			Float valueOf2 = Float.valueOf(value);
			doc.add(new FloatPoint(name, valueOf2));
			doc.add(new StoredField(name, valueOf2));
			break;
		case DoublePoint:
			Double valueOf3 = Double.valueOf(value);
			doc.add(new DoublePoint(name, valueOf3));
			doc.add(new StoredField(name, valueOf3));
			break;
		case BinaryPoint:
			byte[] bytes = value.getBytes();
			doc.add(new BinaryPoint(name, bytes));
			doc.add(new StoredField(name, bytes));
			break;
		case StringField:
			doc.add(new StringField(name, value, Field.Store.YES));
			break;
		case TextField:
			doc.add(new TextField(name, value, Field.Store.YES));
			if(fieldKey.pinyin()) {
				doc.add(new TextField(name+"_pin", pinyin(value), Field.Store.YES));
			}
			break;
		}

		//排序存储
		switch (fieldKey.sort()) {
		case SortNull:
			break;
		case SortedDocValuesField:
			doc.add(new SortedDocValuesField(name, new BytesRef(value)));
			break;
		case SortedSetDocValuesField:
			doc.add(new SortedSetDocValuesField(name, new BytesRef(value)));
			break;
		case NumericDocValuesField:
			doc.add(new NumericDocValuesField(name, Long.valueOf(value)));
			break;
		case SortedNumericDocValuesField:
			doc.add(new SortedNumericDocValuesField(name, Long.valueOf(value)));
			break;
		}
	}

	/**
	 * 中文转拼音操作 (支持挺好)
	 * @param v
	 * @return
	 */
	private static String pinyin(String v) {
		List<String> pinyin = Pinyin.pinyin(v);
		StringBuilder sb = new StringBuilder();
		int size = pinyin.size();
		for (int i = 0; i < size; i++) {
			String val = pinyin.get(i);
			if(val != null) {
				sb.append(val).append(" ");
			}
		}
		return sb.toString();
	}

	public static void main(String[] args) {
	}

}
